import Monitor from "../collection/Monitor"
import { SaveCommand } from "../command/data.command"
import { DeleteSnapshotCommand } from "../command/snapshot.command"
import { DeleteUnusedTourSnapshotsCommand } from "../command/tour.command"
import SettingsData from "../data/SettingsData"
import SnapshotsData from "../data/SnapshotsData"
import SweepData from "../data/SweepData"
import TourData from "../data/TourData"
import EngineContext from "../EngineContext"
import aggregationTypeEnum from "../enum/aggregationType.enum"
import categoryEnum from "../enum/category.enum"
import dataTypeEnum from "../enum/dataType.enum"
import optionsKeyEnum from "../enum/optionsKey.enum"
import storageTypeEnum from "../enum/storageType.enum"
import viewmodeEnum from "../enum/viewmode.enum"
import HighlightReel from "../object/HighlightReel"
import { ObjectSync } from "../storage/DataSync"
import DataSyncStore from "../storage/DataSyncStore"
import Store from "../storage/Store"
import { getDate } from "../utils/date.util"
import Logger from "../utils/Logger"
import Module from "./Module"

const A = new Logger("reel-serializers")
const deserialize = e => {
  if (!e) return null
  const t = new HighlightReel()
  return (
    e.active_reel && e.active_reel.modified && (t.modified = getDate(e.active_reel.modified)),
    e.active_reel && e.active_reel.reel && e.active_reel.reel instanceof Array
      ? (A.info("Reel has " + e.active_reel.reel.length + " items"), t.reel.replace(e.active_reel.reel))
      : A.info("No reel found"),
    t.commit(),
    t
  )
}

const H = new Logger("tour-data")
export default class ToursModule extends Module {
  defaultModes: number[]
  deleteUnusedTourSnapshots: () => Promise<any>
  snapshotsData: SnapshotsData
  tourData: TourData
  engine: EngineContext
  onUpdateSnapshots: any
  store: DataSyncStore
  sweepData: SweepData
  constructor() {
    super(...arguments), (this.name = "tours-data")
    this.defaultModes = [viewmodeEnum.Panorama, viewmodeEnum.Outdoor]
    this.deleteUnusedTourSnapshots = async () => {
      for (const e in this.snapshotsData.collection) {
        const t = this.snapshotsData.collection[e]
        t.category !== categoryEnum.TOUR ||
          this.tourData.isSnapshotInTour(t.sid) ||
          (await this.engine.commandBinder.issueCommand(new DeleteSnapshotCommand(t.sid)).catch(e => {
            H.debug(e)
            H.error(`Failed to delete unused tour snapshot ${t.sid}`)
          }))
      }
    }
    this.onUpdateSnapshots = () => {
      this.tourData.updateSnapshots(this.snapshotsData.collection)
    }
  }
  async init(e, t: EngineContext) {
    const { readonly } = e
    this.engine = t
    const s = await t.market.waitForData(SettingsData),
      n = this.getFilterModes(s, this.defaultModes)
    this.store = this.getStore(e)
    //引擎默认下载导览路径数据//彭蔚
    const r = (await this.store.read()) || new HighlightReel()
    // const r = new HighlightReel()
    this.sweepData = await t.market.waitForData(SweepData)
    this.snapshotsData = await t.market.waitForData(SnapshotsData)
    this.tourData = new TourData(this.snapshotsData.collection, r, n, this.sweepData.getSweepList(), e.looping)
    t.market.register(this, TourData, this.tourData)
    if (!readonly) {
      const e = this.tourData.getReel()
      const i = new Monitor(e, { aggregationType: aggregationTypeEnum.NextFrame }, t)
      i.onChanged(() => this.engine.commandBinder.issueCommand(new SaveCommand({ dataTypes: [dataTypeEnum.HIGHLIGHTS] }))),
        this.store instanceof DataSyncStore && this.store.addMonitor(i)
    }
    this.bindings.push(
      t.commandBinder.addBinding(DeleteUnusedTourSnapshotsCommand, this.deleteUnusedTourSnapshots),
      this.snapshotsData.onChanged(this.onUpdateSnapshots)
    )
    const a = Object.keys(r.reel).length
    const l = this.tourData.getSnapshotCount()
    a !== l && H.info(a - l + " items in snapshots, but not in reel")
  }
  getStore(e) {
    if (this.store) return this.store
    const { modelId, baseUrl, queue } = e
    const n = e.storageProvider || storageTypeEnum.JSONSTORE
    H.info(`Loading Highlight Reel from ${n}`)
    const path = `${baseUrl}/scene-portal/${modelId}/api/highlights`
    const store = new Store.ReadOnlyStore({
      queue,
      path,
      deserialize,
      cachedData: { data: null }
    })
    const sync = new ObjectSync({ publishStores: [store] })
    return new DataSyncStore(sync, {
      dataType: dataTypeEnum.HIGHLIGHTS,
      engine: this.engine
    })
  }
  getFilterModes(e, t) {
    const i = e.tryGetProperty("dh", 1) > 0
    const s = e.tryGetProperty(optionsKeyEnum.Dollhouse, !0)
    i && s && t.push(viewmodeEnum.Dollhouse)
    const r = e.tryGetProperty("fp", 1) > 0
    const o = e.tryGetProperty(optionsKeyEnum.FloorPlan, !0)
    return r && o && t.push(viewmodeEnum.Floorplan), t
  }
}
